package com.hit.dissim.algorithm;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;

public class ARss {
	//传入参数
	private String id1;
	private String id2;
	private int type1 = 3;		//计算aod的时候不需要，需要在选择文件生成map的时候需要
	private int type2 = 3;		
	
//	private static String basedir = "D:\\dissim\\本体";
	static String basedir = "E:\\硕士\\dissim\\本体";
//	static String basedir = findGenes.getRootPath() + "\\FileResource";
	
	
	//树文件
	private static File bpFile = new File(basedir + "\\bp_tree.txt");
	private static File ccFile = new File(basedir + "\\cc_tree.txt");
	private static File doFile = new File(basedir + "\\do_tree.txt");
	private static File totalFile = new File(basedir + "\\total_tree.txt");
	private static File[] treeFiles = new File[]{doFile, bpFile, ccFile, totalFile};
	
	static File refFile = new File(basedir + "\\Ref.txt");
//	private static File refFile = new File(basedir + "pmid_ontology_number.txt");
	
	//aod文件，好像并没有什么用，不需要中间结果
	private Map<String, Double> aodMap1 = new HashMap<String, Double>();	//aod值
	private Map<String, Double> aodMap2 = new HashMap<String, Double>();	//aod值
	
	/**
	 * 两个构造函数
	 */
	public ARss(){
		
	}
	public ARss(String id1,String id2){
		this.id1 = id1;
		this.id2 = id2;
	}
	public ARss(String id1,String id2,int type1,int type2){
		this.id1 = id1;
		this.id2 = id2;
//		this.type1 = type1;
//		this.type2 = type2;
	}
	
	//GO:0005622	GO:0060004
	public static void main(String[] args) {
		ARss arss = new ARss("GO:0042310", "GO:0042310");
		arss.getResult();
//		arss.readFile("hello");
//		Map<String, Set<String>> a = arss.getMap(bpFile);
//		System.out.println("total nodes" + a.size());
//		Node tree = arss.buildTree(a, "GO:0048308");
//		System.out.println(tree.id);
//		System.out.println(tree.s);
//		for(Node c:tree.children){
//			System.out.println(c.toString());
//		}
//		System.out.println("over");
	}
	
	/**
	 * 类初始化后，获取id1、id2等属性后可以工作
	 * @return
	 */
	public double getResult(){
		//根据文件生成map
//		Map<String, Set<String>> map1 = getMap(treeFiles[this.type1]);
//		Map<String, Set<String>> map2 = getMap(treeFiles[this.type2]);
//		System.out.println(map1.size());
//		System.out.println(map2.size());
		Map<String, Set<String>> map = getMap(treeFiles[3]);
		System.out.println("map 长度：" + map.size());
		
		//生成Tree
		Node tree1 = buildTree(map, id1);
		Node tree2 = buildTree(map, id2);
		return this.getRs(tree1, tree2);
	}
	
	/**
	 * 为文件建立映射，映射只跟文件有关,映射的key是父节点，value是子节点组成的集合
	 * 子节点只能有一个父节点。
	 * @param file
	 * @return
	 */
	public Map<String, Set<String>> getMap(File file){
		Map<String, Set<String>> FileMap = new HashMap<String, Set<String>>();
		try {
			Scanner in = new Scanner(new FileInputStream(file));
			in.nextLine();
			while(in.hasNext()){
				String tmp1 = in.next();	//子节点
				String tmp2 = in.next();	//父节点
				if(FileMap.containsKey(tmp2)) {	
					FileMap.get(tmp2).add(tmp1);	//为父节点添加子节点
				} else {
					Set<String> aset = new HashSet<String>();
					aset.add(tmp1);
					FileMap.put(tmp2, aset);	//初始化
				}
			}

			in.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return FileMap;
	}
	
	
	/**
	 * 输入根结点id，构建术语树. 采用递归的方式实现。
	 * @param map
	 * @param id
	 * @return
	 */
	public Node buildTree(Map<String, Set<String>> map, String id) {
		Node root = new Node(id);
		Set<String> aset = map.get(id);	//找到子节点集合
		if(aset == null) {
			return root;
		}
		for(String child:aset) {
			Node anode = buildTree(map, child);
			root.children.add(anode);
			root.s += anode.s;
		}
		
		return root;
	}
	
	/**
	 * 传入两颗术语树，分析两个术语树在文档集Ref下的发生度，//结果存入aodMap中。
	 * @param tree1
	 * @param tree2
	 */
	public double getRs(Node tree1, Node tree2) {
		double acod1 = 0;
		double acod2 = 0;
		double acod = 0;
		System.out.println("tree1.s = " + tree1.s);
		System.out.println("tree2.s = " + tree2.s);
		try {
			Scanner in = new Scanner(new FileInputStream(refFile));
			in.nextLine();
			while(in.hasNextLine()){
				String line = in.nextLine();
				String[] tmp = line.split("[\t|]+");	//通过制表符和|进行分割
				String[] terms = Arrays.copyOfRange(tmp, 1, tmp.length-2);
				int s1 = getS(terms,tree1);
				int s2 = getS(terms,tree2);
				double aod1 = (double)s1/tree1.s;
				double aod2 = (double)s2/tree2.s;
				acod1 += aod1;
				acod2 += aod2;
//				aodMap1.put(terms[0], aod1 * aod1);
//				aodMap2.put(terms[0], aod2 * aod2);
				if(s1 != 0 && s2 != 0) {
					System.out.println(tmp[0] + "  + " + s1 + " " + s2);
					acod += aod1 * aod2;
				}
			}
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		//输出acod
		System.out.println("acod1: " + acod1);
		System.out.println("acod2: " + acod2);
		System.out.println("acod: " + acod);
		
		//计算分值
		double ARs = BaseUtil.getRs(acod, acod1, acod2);
		
		return ARs;
		
		//标准化
//		return BaseUtil.saveRsandStandardize("arss", id1, id2, ARs);
	}
	
	/**
	 * 传入文献和术语树，找到两者之间的s
	 * 本来考虑使用按层遍历的形式，如果节点匹配则加上节点的
	 * @param terms	术语数组
	 * @param tree
	 * @return
	 */
	private int getS(String[] terms, Node tree){
		int s = 0;
		Queue<Node> queue=new LinkedList<Node>();
		queue.add(tree);
		while(queue.size() > 0){
			Node tmp = queue.remove();
			if(ArrayUtils.contains(terms, tmp.id)){		//术语集中是否包含了树的当前节点
				s += tmp.s;
			}
			else {
				if(tmp.children != null)
					for(Node c:tmp.children){
						queue.add(c);
					}
			}
		}
		return s;
	}
	
	/**
	 * Test
	 * @param key
	 */
	public void readFile(String key){
		try {
			Scanner in = new Scanner(new FileInputStream(bpFile));
			in.nextLine();
			while(in.hasNext()){
				String tmp = in.next();
				System.out.println(tmp);
			}
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 树 的节点
	 * @author nokan
	 *
	 */
	class Node {
		String id;	
		int s;		//子孙的节点个数 +1
		Set<Node> children; 	//子孙
		
		Node(String id) {
			this.id = id;
			this.s = 1;
			this.children = new HashSet<Node>();
		}
		
		public String toString() {
			return this.id + "\t" + this.s;
		}
	}
	
}
